package com.xxl.job.executor.mvc.feign;

import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.web.all.common.exception.HandlerException;
import com.netflix.client.ClientException;
import com.netflix.hystrix.exception.HystrixTimeoutException;
import feign.Response;
import feign.RetryableException;
import feign.Util;
import feign.codec.ErrorDecoder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpStatus;

import java.io.IOException;

/**
 * @author lc
 */
@Configuration
public class ExceptionDecoder implements ErrorDecoder {
    private static final Logger log = LoggerFactory.getLogger(ExceptionDecoder.class);

    @Value("${enableLog}")
    public boolean enableLog;

    private static final String UNKNOWN_ERROR= "服务器内部错误";

    @Override
    public Exception decode(String methodKey, Response response) {
        log.info("ExceptionDecoder class");
        log.info("status {} reading {}",response.status(),methodKey);
        if(response.status() == HttpStatus.BAD_REQUEST.value() || response.status() == HttpStatus.NOT_FOUND.value()){
            String logContent = String.format("错误原因：Feign调用：%s status: %s",methodKey,response.status());
            log.error(logContent);
            return new HandlerException(UNKNOWN_ERROR + (enableLog ? logContent:""));
        }
        if(response.status() == HttpStatus.INTERNAL_SERVER_ERROR.value()){
            String body;
            try {
                if (response.body() != null) {
                    body = Util.toString(response.body().asReader());
                    JSONObject jsonObject = JSONUtil.parseObj(body);
                    String logContent = String.format("错误原因：Feign调用：%s 状态: %s body %s",methodKey,response.status(),body);
                    log.info(logContent);
                    return new HandlerException(jsonObject.getStr("message") + (enableLog ? logContent:""));
                }
            } catch (RetryableException retryableException) {
                String logContent = String.format("错误原因：Feign调用：%s 状态: %s 错误类型：RetryableException",methodKey,response.status());
                log.error(logContent);
                return new HandlerException(UNKNOWN_ERROR + (enableLog ? logContent:""));
            }catch (IOException o){
                String logContent = String.format("错误原因：Feign调用：%s 状态: %s 错误类型：IOException",methodKey,response.status());
                log.error(logContent);
                return new HandlerException(UNKNOWN_ERROR + (enableLog ? logContent:""));
            }
        }
        return new HandlerException(UNKNOWN_ERROR);
    }

    /**
     * 判断错误类型，返回一个可返回给前端的log
     * @param cause 错误
     * @param className 类名称
     * @return log内容
     */
    public void check(final Throwable cause, final String className){
        String logContent = "";
        //情况为已经调通的情况下，抛出了自定义异常
        if(cause instanceof HandlerException){
            logContent = cause.getMessage();
            //熔断超时
        }else if(cause instanceof HystrixTimeoutException){
            logContent = String.format("Feign服务调用失败，client:%s; 错误类型：HystrixTimeoutException；失败原因：%s",className,cause.getMessage());
            //重试异常
        }else if(cause instanceof RetryableException){
            logContent = String.format("Feign服务调用失败，client:%s;错误类型：RetryableException；失败原因%s",className,cause.getCause().getMessage());
            //feign连接不通
        }else if(cause instanceof RuntimeException && cause.getCause() instanceof ClientException){
            logContent = String.format("Feign服务调用失败，client:%s;错误类型：ClientException；失败原因%s",className,cause.getCause().getMessage());
            //其他异常
        }else {
            logContent = String.format("Feign服务调用失败，client:%s;失败原因未知",className);
        }
            log.error(logContent);
    }
}
